import io
import json
import os
import platform
import re
import shutil
import subprocess
import warnings
from copy import copy
from datetime import datetime
from io import StringIO
from pathlib import Path
from typing import Any, Literal
import fitz
import numpy
import pandas
import plotly.colors
import pyproj
import rasterio
import requests
import yaml
from openpyxl import load_workbook
from openpyxl.cell import Cell, MergedCell
from openpyxl.drawing.image import Image
from openpyxl.styles import Alignment, Border, Side
from rasterio.enums import ColorInterp
from rasterio.profiles import default_gtiff_profile
from ..dataclass.results import DocData, GeoReferenceInfo
from ..dataclass.tables import FieldMetadata, TableCollection, TableData
from ..dataclass.terminologies import DataTypes, GeneralProps, Units

current_dir: Any
config_file_path: Any
config: Any

def convert_pdf_to_images(pdf_path: Any, output_path: Any = None, dpi: int = 200, format: Literal[Any, Any, Any] = "png", image_prefix: str = "image", first_page: int = 1, last_page: Any = None, width: Any = None, height: Any = None):
    """
    Convert pdf document to images.
    
    Parameters
    ----------
    pdf_path: str | Path | None, default: None
        The document's path
    
    output_path: str | Path | None, default: None
        The folder to save images. If None, save in the current working directory
    
    dpi: int, default: 200
        The DPI of the picture converted from document
    
    format: Literal["png", "jpg", "jpeg"], default: "png"
        The format of the images converted from pdf
    
    image_prefix: str, default: "image"
        The prefix of the images converted from pdf
    
    first_page: int, default: 1
        The first page to convert (1-based)
    
    last_page: int | None, default: None
        The last page to convert (1-based, inclusive). If None, convert all pages
    
    width: int | None, default: None
        The width of the picture converted from document. If None, use DPI
    
    height: int | None, default: None
        The height of the picture converted from document. If None, use DPI
    
    Returns
    -------
    list[str]
        The list of image file paths
    
    Raises
    ------
    ValueError
        If pdf_path is None or file doesn't exist
    Exception
        If PDF conversion fails
    """
    ...
def convert_multiple_pdfs_to_images(pdf_paths: list[Any], output_paths: Any = None, dpi: int = 200, format: Literal[Any, Any, Any] = "png", image_prefixes: Any = "image", first_pages: Any = 1, last_pages: Any = None, widths: Any = None, heights: Any = None) -> list[str]:
    """
    Convert multiple PDF documents to images.
    
    Parameters
    ----------
    pdf_paths: list[str | Path]
        List of PDF file paths
    
    output_paths: list[str | Path] | str | Path | None, default: None
        List of folders to save images for each PDF, or single folder for all PDFs
    
    dpi: int, default: 200
        The DPI of the pictures converted from documents
    
    format: Literal["png", "jpg", "jpeg"], default: "png"
        The format of the images converted from PDFs
    
    image_prefixes: list[str] | str, default: "image"
        List of prefixes for each PDF, or single prefix for all PDFs
    
    first_pages: list[int] | int, default: 1
        List of first pages for each PDF, or single first page for all PDFs (1-based)
    
    last_pages: list[int | None] | int | None, default: None
        List of last pages for each PDF, or single last page for all PDFs (1-based, inclusive)
    
    widths: list[int | None] | int | None, default: None
        List of widths for each PDF, or single width for all PDFs
    
    heights: list[int | None] | int | None, default: None
        List of heights for each PDF, or single height for all PDFs
    
    Returns
    -------
    list[str]
        List of all image file paths from all PDFs
    
    Raises
    ------
    ValueError
        If pdf_paths is empty or parameter lists have mismatched lengths
    """
    ...
def get_csv_from_stream(url: str, host: Any = None) -> Any:
    """
    Fetch CSV data from a MinIO data stream URL without downloading the file.
    Handles Chinese character encoding properly.
    
    Parameters
    ----------
    url: str
        The url of the csv file.
        If the url is not a full url, the host will be added automatically.
    
    host: str | None, default: None
        The host of the platform.
    """
    ...

class MDBHandler:
    def __init__(self):
        """MDB文件处理器的构造函数"""
        ...
    def create_empty_mdb(self, output_file: str) -> Any:
        """
        创建一个空白的MDB文件
        
        Parameters
        ----------
        output_file (str): 输出MDB文件路径
        """
        ...
    def read_mdb(self, file_path: Any) -> Any:
        """
        跨平台读取 MDB 文件中的所有表
        
        Parameters
        ----------
        file_path (str | Path): MDB文件路径
        
        Returns
        -------
        TableCollection | None: 表集合，失败时返回 None
        """
        ...
    def write_to_mdb(self, output_file: str) -> Any:
        """
        将所有表写入MDB文件
        如果文件不存在，则创建新文件
        如果表已存在，则先删除再创建
        
        Parameters
        ----------
        output_file (str): 输出MDB文件路径
        """
        ...
    def clear_mdb_tables_data(self, mdb_path: str) -> Any:
        """
        清空指定MDB文件中的所有表数据（保留表结构）
        
        Parameters
        ----------
        mdb_path : str
            需要清空数据的MDB文件路径
        """
        ...

class ExcelImage:
    """
    Represents an image to be inserted into an Excel worksheet.
    Similar to docxtpl's InlineImage but for Excel using openpyxl.
    """
    def __init__(self, image_path: Any, width: Any = None, height: Any = None) -> Any:
        """
        Initialize an ExcelImage object.
        
        Args:
            image_path: Path to the image file
            width: Image width in meters (optional). If only width is specified,
                   height will be calculated to maintain aspect ratio.
            height: Image height in meters (optional). If only height is specified,
                    width will be calculated to maintain aspect ratio.
        
        Note:
            - If only width OR height is specified, aspect ratio is preserved
            - If both width AND height are specified, exact dimensions are used (may distort image)
            - If neither is specified, original image size is used
        """
        ...
    @property
    def openpyxl_image(self) -> Image:
        """Get the underlying openpyxl Image object."""
        ...

class ExcelTemplate:
    def __init__(self, template: Any) -> Any:
        ...
    def render(self, doc_data: DocData, include_table_titles: bool = False, apply_table_borders: bool = False, border_style: str = "thin", image_size_type: Any = "width", image_size: Any = None) -> bool:
        """
        Render a complete DocData structure into an Excel file using the template.
        
        Args:
            doc_data: DocData dictionary with 'data' and 'doc_keys_struct'.
            include_table_titles: If True, table headers will be inserted. If False,
                                headers are assumed to be already in the template.
            apply_table_borders: If True, apply borders to all table regions.
            border_style: Border style for tables - "thin", "medium", "thick", "double", "dashed", "dashDot",
                "dashDotDot", "hair", "mediumDashed", "mediumDashDot", "mediumDashDotDot", "slantDashDot" etc.
            image_size_type: The type of the image size.
                If "width", the image size will be set to the width of the image (height calculated to maintain aspect ratio).
                If "height", the image size will be set to the height of the image (width calculated to maintain aspect ratio).
                If dict, different key can use different type of image size. If the key is not found, "width" will be used as default.
            image_size: The size of the image in meters.
                If dict[str, float], key is the key in the doc_data and the value is the size of the image in meters.
                If dict[str, list[float]], key is the key in the doc_data and the value is the size for each image in the list in meters.
                If None, the image size will be as same as its original size.
                Note: Aspect ratio is always preserved when resizing.
        
        Returns:
            True if successful, False otherwise
        """
        ...
    def save(self, file_name: Any) -> Any:
        ...

class VrtHandler:
    """Handler for processing VRT (Virtual Raster) files and converting them to TableData/TableCollection."""
    def __init__(self, target_crs: Any = None, subsample_factor: Any = None, time_info_pattern: Any = None):
        """
        Initialize VrtHandler.
        
        Parameters
        ----------
        target_crs : str | None, default: None
            Target coordinate reference system for coordinate transformation. If None, uses the original CRS from VRT.
        
            Supported CRS formats:
            - **EPSG codes**: "EPSG:4326" (WGS84 lat/lon), "EPSG:3857" (Web Mercator), "EPSG:32633" (UTM Zone 33N)
            - **PROJ4 strings**: "+proj=longlat +datum=WGS84", "+proj=merc +a=6378137 +b=6378137"
            - **Well-known names**: "WGS84", "EPSG:4326", "NAD83", "NAD27"
            - **WKT strings**: Full Well-Known Text representation
            - **Authority codes**: "EPSG:4326", "ESRI:102100"
        
            Common examples:
            - "EPSG:4326": WGS84 Geographic (lat/lon in degrees) - **recommended for web mapping**
            - "EPSG:3857": Web Mercator (meters) - used by Google Maps, OpenStreetMap
            - "EPSG:4269": NAD83 Geographic (North America)
            - "EPSG:32633": UTM Zone 33N (meters, Europe)
            - "+proj=longlat +datum=WGS84": PROJ4 string for WGS84
        
            **Note**: If transformation is applied, coordinate column names will change:
            - Geographic CRS → "longitude", "latitude" columns
            - Projected CRS → "x_coordinate", "y_coordinate" columns
        
        subsample_factor : int | None, default: None
            Factor to subsample large rasters. If None, reads full resolution.
            E.g., subsample_factor=5 reads every 5th pixel.
        
        time_info_pattern : str | None, default: None
            Regex pattern to extract time information from filename
            If None, uses default patterns
        """
        ...
    def read_single_vrt(self, vrt_path: Any, time_check: bool = False) -> tuple[TableData, GeoReferenceInfo]:
        """
        Read a single VRT file and convert to TableData.
        
        Parameters
        ----------
        vrt_path : str | Path
            Path to the VRT file
        
        time_check : bool, default: False
            Whether to check time information can be extracted from the vrt name.
        
        Returns
        -------
        tuple[TableData, GeoReferenceInfo]
            TableData with spatial coordinates and values, and georeference info.
        """
        ...
    def read_time_series_vrt(self, directory_path: Any, pattern: Any = None) -> tuple[TableCollection, Any]:
        """
        Read all VRT files at different time in a directory and convert to TableCollection.
        
        Parameters
        ----------
        directory_path : str | Path
            Path to directory containing VRT files at different time
        
        pattern : str | None, default: None
            File pattern to match (e.g., "*.vrt", "Depth*.vrt")
            If None, matches all .vrt files
        
        Returns
        -------
        tuple[TableCollection, dict[str, GeoReferenceInfo]]
            TableCollection with all VRT data, and georeference info for each VRT file
        
        Note
        ----
        The tables are sorted by their time information from earliest to latest.
        """
        ...
    def generate_geotiff(self, vrt_path: Any = None, directory_path: Any = None, output_path: Any = None, colormap: Any = None, pattern: Any = None, format: Literal[Any, Any] = "geotiff", compress: str = "lzw", predictor: int = 2) -> list[Path]:
        """
        Generate GeoTIFF or PNG files from VRT file(s) with colormap and transparency support.
        
        Parameters
        ----------
        vrt_path : str | Path | None, default: None
            Path to a single VRT file. Mutually exclusive with directory_path.
        
        directory_path : str | Path | None, default: None
            Path to directory containing VRT files for time series processing.
            Mutually exclusive with vrt_path.
        
        output_path : str | Path | None, default: None
            Output directory for generated files.
            If None, creates output in same directory as input with format-specific suffix.
        
        colormap : str | dict | None, default: None
            Colormap specification. Can be:
            - **Plotly colorscale name**: "viridis", "plasma", "inferno", "magma", "cividis",
              "turbo", "rainbow", "jet", "hot", "cool", "RdYlBu", "RdBu", "Spectral", etc.
            - **Custom dict**: {value: [r, g, b, a]} where values are 0-1 floats or 0-255 integers
              Example: {0.0: [0, 0, 255, 255], 0.5: [255, 255, 0, 255], 1.0: [255, 0, 0, 255]}
            - **None**: Uses default "viridis" colorscale
        
        pattern : str | None, default: None
            File pattern to match when processing directory (e.g., "*.vrt", "Depth*.vrt").
            Only used when directory_path is provided.
        
        format : Literal["geotiff", "png"], default: "geotiff"
            Output format:
            - **"geotiff"**: Generates .tif files with embedded geospatial metadata
            - **"png"**: Generates .png files with separate .pgw (world file), .prj (projection),
              and metadata.json files for GIS compatibility
        
        compress : str, default: "lzw"
            Compression method for GeoTIFF. Only used when format="geotiff".
        
            Options and recommendations:
            - **"lzw"** (default): Lossless, good compression ratio, widely supported.
              Best for: Most raster data, scientific data, when file size matters.
            - **"deflate"**: Lossless, similar to LZW but sometimes better compression.
              Best for: Alternative to LZW, some software prefers deflate.
            - **"jpeg"**: Lossy compression, smallest files but quality loss.
              Best for: RGB imagery where small quality loss is acceptable.
              Note: Not suitable for scientific data or single-band rasters.
            - **"none"**: No compression, largest files but fastest access.
              Best for: When processing speed is critical, temporary files.
        
        predictor : int, default: 2
            Predictor for lossless compression optimization. Only used when format="geotiff"
            and compress is "lzw" or "deflate".
        
            Options and recommendations:
            - **1** (none): No prediction, compress data as-is.
              Best for: Random/noisy data, already compressed data.
            - **2** (horizontal differencing, default): Stores differences between adjacent pixels.
              Best for: Most imagery, gradual spatial changes, typical raster data.
              Typical improvement: 20-50% better compression for spatial data.
            - **3** (floating point): Optimized for floating-point scientific data.
              Best for: Elevation models, temperature data, continuous surfaces.
              Typical improvement: 40-60% better compression for float32/64 data.
        
        Returns
        -------
        list[Path]
            List of paths to generated files (main image files: .tif or .png).
        
        Raises
        ------
        ValueError
            If both vrt_path and directory_path are provided or if neither is provided.
            If colormap format is invalid.
        
        FileNotFoundError
            If specified files or directories don't exist.
        
        Examples
        --------
        Generate GeoTIFF from single VRT with viridis colormap:
        
        >>> handler = VrtHandler()
        >>> output_files = handler.generate_geotiff(
        ...     vrt_path="flood_depth.vrt",
        ...     colormap="viridis",
        ...     format="geotiff"
        ... )
        
        Generate PNG series with georeference files and custom colormap:
        
        >>> custom_colormap = {
        ...     0.0: [0, 0, 255, 255],      # Blue for low values
        ...     0.5: [255, 255, 0, 255],    # Yellow for medium values
        ...     1.0: [255, 0, 0, 255]       # Red for high values
        ... }
        >>> output_files = handler.generate_geotiff(
        ...     directory_path="time_series_vrts/",
        ...     colormap=custom_colormap,
        ...     format="png"
        ... )
        
        Note
        ----
        PNG format generates additional files:
        - image.png: RGBA image with applied colormap
        - image.pgw: World file for geospatial positioning
        - image.prj: Projection information file
        - metadata.json: Colormap and time information (one per output directory)
        """
        ...
